/*
 * GameWorld.java
 *
 * Created on 29 October 2006, 16:33
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package digitrix.fightclub.game;

import digitrix.fightclub.util.CustomFont;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Random;
import java.util.Vector;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.LayerManager;

/**
 *
 * @author Josh
 */
public class World extends LayerManager {
    
    private static World _instance;
        
    private static final int BTM_IMAGE_TO_FLOOR_BUF = 50;
    private static final int DANGER_ZONE = 27;    // helper variable used by the AI to determine whether to talk forward or not, this value will
    // indicate the distance that the ai should become wary of his opponent
    
    // game stat constants
    public static final int NO_ROUNDS = 3;     
    public static final int DRAW = 0;
    public static final int PLAYER_WINS = 1;
    public static final int OPPONENT_WINS = 2; 
            
    // players
    public static final int PLAYER_1 = 1;
    public static final int PLAYER_2 = 2;
    public static final int PLAYER_3 = 3;
    public static final int PLAYER_4 = 4;
    
    // image paths
    private static final int BACKDROP_COUNT = 3;
    private static final String IMGPATH_BACKDROP = "/digitrix/fightclub/res/backdrop#.png";
    private static final String IMGPATH_SPECIAL_EFFECTS = "/digitrix/fightclub/res/effects.png";
    private static final String IMGPATH_ROUND_WON = "/digitrix/fightclub/res/roundwon.png";
    
    private static final String IMGPATH_PLAYER_STANDING = "/digitrix/fightclub/res/player#_standing.png";
    private static final String IMGPATH_PLAYER_WALKING = "/digitrix/fightclub/res/player#_walking.png";
    private static final String IMGPATH_PLAYER_ATTACK1 = "/digitrix/fightclub/res/player#_attack1.png";
    private static final String IMGPATH_PLAYER_ATTACK2 = "/digitrix/fightclub/res/player#_attack2.png";
    private static final String IMGPATH_PLAYER_ATTACK3 = "/digitrix/fightclub/res/player#_attack3.png";
    private static final String IMGPATH_PLAYER_FALLING = "/digitrix/fightclub/res/player#_falling.png";
    private static final String IMGPATH_PLAYER_DYING = "/digitrix/fightclub/res/player#_dying.png";
    
    // sprite image index
    private static final int IMGINDEX_STANDING  = 0;
    private static final int IMGINDEX_WALKING   = 1;
    private static final int IMGINDEX_ATTACK1   = 2;
    private static final int IMGINDEX_ATTACK2   = 3;
    private static final int IMGINDEX_ATTACK3   = 4;
    private static final int IMGINDEX_FALLING   = 5;
    private static final int IMGINDEX_DYING     = 6;
    
    // attack damage constants
    private static final int ATTACK1_DAMAGE     = 1;
    private static final int ATTACK2_DAMAGE     = 3;
    private static final int ATTACK3_DAMAGE     = 6;
    
    // colour constants
    private static final int BG_COL_DEFAULT = 0x84E5F8;
    
    private int _screenWidth = 0;
    private int _screenHeight = 0;
    
    private int _worldBGColour = BG_COL_DEFAULT;
    
    private Image _imgBackdrop = null;
    private Image _imgRoundWon = null; 
    private Image _imgSpecialEffects = null;
    private Image[] _imgsPlayer = null;
    private Image[] _imgsOpponent = null;
    private Image _imgPlayersEnergy = null;
    private Image _imgOpponentsEnergy = null;
    
    private Fighter _player = null;
    private Fighter _opponent = null;
    private Vector _specialEffects = null; // pool of special effects
    
    // status bar positions
    private int _worldStatusX1 = 0;
    private int _worldStatusX2 = 0;
    private int _worldStatusX3 = 0;
    private int _worldStatusY = 0;
    private int _engergyBarWidth = 60;
    
    private int _worldWidthX1 = 0;
    private int _worldWidthX2 = 0;
    private int _worldHeightY1 = 0; // world top
    private int _worldHeightY2 = 0; // world floor
    private int _worldsCenterX = 0;
    private int _worldsCenterY = 0;
    private int _statusBarHeight = 50; // default value
    
    private int _round = 1; // fighting rounds
    private int _roundsWonPlayer = 0;
    private int _roundsWonOpponent = 0;
    
    private static final int GS_TIME_FIGHTING = 60;
    private int _time = 0;
    private long _timeUpdated = 0;
    
    private GameManager _gameManager = null; 
    
    /** Creates a new instance of GameWorld */
    public World( GameManager gameManager, int screenWidth, int screenHeight ) throws Exception {
        super();
        
        _instance = this;
        _gameManager = gameManager; 
        
        _screenWidth = screenWidth;
        _screenHeight = screenHeight;
        
        loadImages();
        
    }
    
    public void initFight( int playerID, int opponentID, boolean mutliplayer ){
        
        clearStage();
        loadBackdrop();
        
        // load fighters images
        _imgsPlayer = initPlayerImages( playerID );
        _imgsOpponent = initPlayerImages( opponentID );
        
        // initilise fighters
        _player = initPlayer( playerID, false, _imgsPlayer );
        if( mutliplayer ){
            _opponent = initPlayer( opponentID, true, _imgsOpponent );
            //_opponent.setReverseMovemet( true ); 
        }
        else{
            _opponent = initPlayer( opponentID, true, _imgsOpponent, true );
        }
        
        // add fighters to the stage
        append( _player );
        append( _opponent );
        
        // add special effects
        initSpecialEffects();
        
        // update energy levels
        redrawEnergyBars();
        
        _timeUpdated = System.currentTimeMillis();
        _time = GS_TIME_FIGHTING;
        
        _round = 1;
        _roundsWonPlayer = 0;
        _roundsWonOpponent = 0; 
        
        setViewWindow( 0, 0, _screenWidth, _screenHeight );
    }
    
    public void fightAgain(){
        _round=1; 
        _roundsWonPlayer = 0;
        _roundsWonOpponent = 0; 
        
        loadBackdrop(); // change background
        
        _player.reset();
        _opponent.reset(); 
        
        // update energy levels
        redrawEnergyBars();        
        
        // reset fighting time
        _timeUpdated = System.currentTimeMillis();
        _time = GS_TIME_FIGHTING;
    }
    
    public void nextRound(){
        _round++; 
        
        loadBackdrop(); // change background
        
        _player.reset();
        _opponent.reset(); 
        
        // update energy levels
        redrawEnergyBars();
        
        // reset fighting time
        _timeUpdated = System.currentTimeMillis();
        _time = GS_TIME_FIGHTING;
    }
    
    public static World getInstance(){
        return _instance;
    }
    
    /**
     * Called by the Game Manager at every cycle to update the viewport in that the user is always in the center of the
     * screen (unless the end of the level has been hit) as well as implement our parallax scrolling for the
     * background image :)
     **/
    public void tick( long elapsedTime ){
        // ideas - gets darker as the timer ticks down?
        
        // reduce the time by one if a second has passed
        if( System.currentTimeMillis() - _timeUpdated > 1000 ){
            _timeUpdated = System.currentTimeMillis();
            _time--;
        }
        
        // if time is over then notify the game manager
        if( _time <= 0 ){
            GameManager.getInstance().setState( GameManager.GS_FIGHTOVER );
        }
        
    }
    
    public void tickSpecialEffects( long elapsedTime ){
        Enumeration enumEffects = _specialEffects.elements();
        while( enumEffects.hasMoreElements() ){
            ((SpecialEffect)enumEffects.nextElement()).tick( elapsedTime );
        }
    }
    
    public void addSpecialEffect( int type, Actor actor ){
        // check if we have any elements in the queue
        SpecialEffect effect = null;
        
        if( _specialEffects.size() <= 0 ){
            effect = new SpecialEffect( _imgSpecialEffects );
            insert( effect, 0 ); // add to our world
        } else{
            // test if the last item in the vector is invisible, if so then use this one
            effect = (SpecialEffect)_specialEffects.lastElement();
            if( effect.isVisible() ){
                // leave the effect where it is and generate a new one (just change the reference
                // to a new object)
                effect = new SpecialEffect( _imgSpecialEffects );
                insert( effect, 0 ); // add to our world
            }
            // otherwise (if we're going to use this game effect) then
            // remove it from the queue so we can place it at the top/start of
            // the queue
            else{
                _specialEffects.removeElement( effect );
            }
        }
        
        // add it at the front of the queue
        _specialEffects.insertElementAt( effect, 0 );
        
        // find position according to actor and type of special effect
        int x = 0;
        int y = 0;
        switch( type ){
            case SpecialEffect.SPECIAL_EFFECT_HIGH_FIRE_KICK:
                if( actor.isFacingLeft() ){
                    x = actor.getX() - 9;
                } else{
                    x = actor.getX()+actor.getWidth()/2 + 9;
                }
                y = actor.getY();
                break;
            case SpecialEffect.SPECIAL_EFFECT_LOW_FIRE_KICK:
                if( actor.isFacingLeft() ){
                    x = actor.getX() - 9;
                } else{
                    x = actor.getX()+actor.getWidth()/2 + 9;
                }
                y = actor.getY() + 22;
                break;
        }
        
        // initilise the effect
        effect.init( type, x, y, actor.isFacingLeft() );
    }
    
    //<editor-fold defaultstate="collapsed" desc="Painting helper functions">
    
    public Image ZoomIn(Image img) {
        
        Image outImg = null;
        
        int[] rgbOutput = null;
        Graphics g = null;
        int width = 0,height = 0;
        
        try {
            
            width  =  img.getWidth();
            height = img.getHeight();
            
            outImg  = Image.createImage(width<<1,height<<1);
            
            int rgbInput[]=new int[width*height];
            rgbOutput = new int[(width<<1)*(height<<1)];
            
            img.getRGB(rgbInput,0,width,0,0,width,height);
            
            int i,j,k;
            k=0;
            for(i=0;i<(height<<1);i+=2) {
                for(j=0;j<(width<<1);j+=2) {
                    rgbOutput[i*(width<<1) + j] = rgbInput[k] ;
                    rgbOutput[(i+1)*(width<<1) + j]  = rgbInput[k];
                    rgbOutput[i*(width<<1) + j+1]  = rgbInput[k];
                    rgbOutput[(i+1)*(width<<1) + j+1]  = rgbInput[k];
                    k++;
                }
            }
            
            g = outImg.getGraphics();
        } catch(Exception e){
            System.out.println( "e " + e.toString() );
        }
        
        return outImg.createRGBImage(rgbOutput,width<<1,height<<1,true);
    }
    
    public void updatePlayersEnergyBar(){
        // update players energy bar
        Graphics g = _imgPlayersEnergy.getGraphics();
        
        // clear background
        g.setColor(0);
        g.fillRect( 0, 0, _imgPlayersEnergy.getWidth(), _imgPlayersEnergy.getHeight() );
        
        // draw a whiteish border
        g.setColor(0xaaaaaa);
        g.fillRect( 0, 0, _engergyBarWidth, 12 );
        
        if( _player.isCritical() ){
            g.setColor( 0xcc2222 );
        } else{
            g.setColor( 0x22cc22 );
        }
        
        // work out the width of their current energy levels
        int playersStatus = _player.getHealth()*3;
        
        g.fillRect( 1, 1, playersStatus, 12 );
    }
    
    public void updateOpponentsEnergyBar(){
        // update opponents energy bar
        Graphics g = _imgOpponentsEnergy.getGraphics();
        
        // clear background
        g.setColor(0);
        g.fillRect( 0, 0, _imgPlayersEnergy.getWidth(), _imgPlayersEnergy.getHeight() );
        
        // draw a whiteish border
        g.setColor(0xaaaaaa);
        g.fillRect( 0, 0, _engergyBarWidth, 12 );
        
        if( _opponent.isCritical() ){
            g.setColor( 0xcc2222 );
        } else{
            g.setColor( 0x22cc22 );
        }
        
        // work out the width of their current energy levels
        int playersStatus = _opponent.getHealth()*3;
        
        g.fillRect( 1, 1, playersStatus, 12 );
    }
    
    public void redrawEnergyBars(){
        updateOpponentsEnergyBar();
        updatePlayersEnergyBar();
        
    }
    
    public void printTime( int text, Graphics g, int x, int y ){
        CustomFont cfont = FightClub.getInstance().getGameFont();
        if(  cfont == null )
            return;
        
        String strText = Integer.toString( text );
        if( strText.length() < 2 ){
            strText = "0" + strText;
        }
        
        if( strText.length() < 3 ){
            strText = "0" + strText;
        }
        
        cfont.drawLargeString( strText, x, y, g );
        
    }
    
    public void paint( Graphics g, int x, int y, int screenWidth, int screenHeight ){
        
        if( _imgBackdrop != null )
            g.drawImage( _imgBackdrop, _worldWidthX1, _worldHeightY1, Graphics.LEFT | Graphics.TOP );
        
        // paint the other layers
        super.paint( g, x, y );
        
        // draw energy bar 
        g.drawImage( _imgPlayersEnergy, _worldStatusX1, _worldStatusY, Graphics.TOP | Graphics.LEFT );
        g.drawImage( _imgOpponentsEnergy, _worldStatusX3, _worldStatusY, Graphics.TOP | Graphics.LEFT );
        
        // draw stars for the rounds won for each player
        if( _roundsWonPlayer > 0 ){
            for( int i=0; i<_roundsWonPlayer; i++ ){
                g.drawImage( _imgRoundWon, _worldStatusX1+(i*17), _worldStatusY+17, Graphics.TOP | Graphics.LEFT );
            }
        }
        
        if( _roundsWonOpponent > 0 ){
            for( int i=0; i<_roundsWonOpponent; i++ ){
                g.drawImage( _imgRoundWon, (_worldStatusX3+_imgOpponentsEnergy.getWidth())-((i+1)*17), _worldStatusY+17, Graphics.TOP | Graphics.LEFT );
            }
        }
        
        // draw time
        printTime( _time, g, _worldStatusX2, _worldStatusY );
        
    }
    
//</editor-fold>
    
//<editor-fold defaultstate="collapsed" desc="Helper functions for initilising game components">
    
    private void clearStage(){
        while( this.getSize() > 0 )
            remove( getLayerAt(0) );
        
        // clear special effects
        //_specialEffects.removeAllElements();
        
    }
    
    private void initSpecialEffects(){
        SpecialEffect effect = null;
        
        // load image
        if( _imgSpecialEffects == null ){
            try{
                _imgSpecialEffects = Image.createImage( IMGPATH_SPECIAL_EFFECTS );
            } catch( IOException e ){ return; }
        }
        
        // create inital pool of special effects
        if( _specialEffects == null ){
            _specialEffects = new Vector();
            
            effect = new SpecialEffect( _imgSpecialEffects );
            _specialEffects.addElement( effect );
            
        }
        
        // make sure all special effects are reset and added to the layer manager (as we clear out all objects
        // when we initilise a new fight)
        Enumeration enumEffects = _specialEffects.elements();
        while( enumEffects.hasMoreElements() ){
            effect = (SpecialEffect)enumEffects.nextElement();
            effect.setVisible( false );
            insert( effect, 0 );
        }
    }
    
    private void loadImages(){
        try{
            _imgPlayersEnergy = Image.createImage( _engergyBarWidth, 14 );
            _imgOpponentsEnergy = Image.createImage( _engergyBarWidth, 14 );
            _imgRoundWon = Image.createImage( IMGPATH_ROUND_WON );             
        } catch( Exception e ){
            System.out.println( "[ERR] World.loadImages - " + e.getMessage() );
        }
        
    }
    
    private void loadBackdrop(){
        
        // select backdrop
        Random rand = new Random();
        int statusBuffer = 3; 
        
        
        int i = 0; // image id
        if( _gameManager.getGameMode() == FightClub.GAME_MODE_PRACTICE ){
            i = rand.nextInt( BACKDROP_COUNT ); // select a random number between 0 and 2
        }
        else{
            if( getRound() == 1 )
                i = 0;
            else if( getRound() == 2 )
                i = 1;
            else
                i = 2; 
        }
        
        try{
            _imgBackdrop = Image.createImage( IMGPATH_BACKDROP.replace( '#', Integer.toString( i ).toCharArray()[0] ) );
        } catch( IOException e ){
            System.out.println( "[ERR] World.loadBackdrop - " + e.getMessage() );
            return;
        }
        
        // now work out the world limits
        if( _imgBackdrop.getWidth() > _screenWidth ){
            _worldWidthX1 = 0;
            _worldWidthX2 = _screenWidth;
            
            // status positions
            _worldStatusX1 = 0+statusBuffer;
            _worldStatusX2 = _screenWidth/2-18;
            _worldStatusX3 = _screenWidth-(_engergyBarWidth+statusBuffer);
            
            _worldsCenterX = _screenWidth/2;
        } else{
            int diff = (_screenWidth - _imgBackdrop.getWidth())/2;
            _worldWidthX1 = diff;
            _worldWidthX2 = diff+_imgBackdrop.getWidth();
            
            // status positions
            _worldStatusX1 = diff+statusBuffer;
            _worldStatusX2 = (diff+_imgBackdrop.getWidth()/2)- 18;
            _worldStatusX3 = (diff+_imgBackdrop.getWidth())-(_engergyBarWidth+statusBuffer);
            
            _worldsCenterX = diff+_imgBackdrop.getWidth()/2;
        }
        
        if( _imgBackdrop.getHeight() > _screenHeight ){
            _worldHeightY1 = 0;
            _worldHeightY2 = _screenHeight - BTM_IMAGE_TO_FLOOR_BUF;
            
            // status bar vertical psotion
            _worldStatusY = 0;
            
            _worldsCenterY = _screenHeight/2; 
        } else{
            _worldHeightY1 = (_screenHeight-_imgBackdrop.getHeight())/2;
            if( (_imgBackdrop.getHeight()+_worldHeightY1) > _screenHeight )
                _worldHeightY2 = _screenHeight - 5;
            else
                _worldHeightY2 = (_worldHeightY1 + _imgBackdrop.getHeight()) - BTM_IMAGE_TO_FLOOR_BUF;
            
            _worldStatusY = _worldHeightY1 + 4;
            //while( (_worldStatusY++) < 0 ); // incremement just in-case we go off the screen
            
            _worldsCenterY = _worldHeightY1 + _imgBackdrop.getHeight()/2;
        }
    }
    
    private Image[] initPlayerImages( int playerID ){
        Image[] images = null;
        
        // see if the images are loaded
        if( _player != null && _player.getPlayerID() == playerID ){
            images = _imgsPlayer;
        }
        
        if( _opponent != null && _opponent.getPlayerID() == playerID ){
            images = _imgsOpponent;
        }
        
        if( images == null ){
            images = new Image[7];
            
            try{
                images[IMGINDEX_STANDING] = Image.createImage( IMGPATH_PLAYER_STANDING.replace( '#', Integer.toString( playerID ).toCharArray()[0] ) );
                images[IMGINDEX_WALKING] = Image.createImage( IMGPATH_PLAYER_WALKING.replace( '#', Integer.toString( playerID ).toCharArray()[0] ) );
                images[IMGINDEX_ATTACK1] = Image.createImage( IMGPATH_PLAYER_ATTACK1.replace( '#', Integer.toString( playerID ).toCharArray()[0] ) );
                images[IMGINDEX_ATTACK2] = Image.createImage( IMGPATH_PLAYER_ATTACK2.replace( '#', Integer.toString( playerID ).toCharArray()[0] ) );
                images[IMGINDEX_ATTACK3] = Image.createImage( IMGPATH_PLAYER_ATTACK3.replace( '#', Integer.toString( playerID ).toCharArray()[0] ) );
                images[IMGINDEX_FALLING] = Image.createImage( IMGPATH_PLAYER_FALLING.replace( '#', Integer.toString( playerID ).toCharArray()[0] ) );
                images[IMGINDEX_DYING] = Image.createImage( IMGPATH_PLAYER_DYING.replace( '#', Integer.toString( playerID ).toCharArray()[0] ) );
            } catch( IOException e ){
                System.out.println( "unable to load image; " + e.getMessage() );
            }
        }
        
        return images;
    }
    
    private Fighter initPlayer( int playerID, boolean facingLeft, Image[] images ){
        return initPlayer( playerID, facingLeft, images, false );
    }
    
    private Fighter initPlayer( int playerID, boolean facingLeft, Image[] images, boolean isComputer ){
        
        // if player has already been init then just reset the player
        /*if( fighter != null && fighter.getPlayerID() == playerID ){
            fighter.setFacingLeft( facingLeft );
            fighter.reset();
            return;
        }*/
        
        Fighter fighter = null;
        Vector states = new Vector();
        ActorState state = null;
        
        // create the fighter
        if( isComputer )
            fighter = new AIFighter( images[IMGINDEX_STANDING], 24, 41, playerID );
        else
            fighter = new Fighter( images[IMGINDEX_STANDING], 24, 41, playerID );
        
        switch( playerID ){
            case PLAYER_1:
                //<editor-fold defaultstate="collapsed" desc="player 1 state config">
                // STANDING STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_STANDING );
                state.setFrames( images[IMGINDEX_STANDING] );
                state.setFrameWidth( 24 ); state.setFrameHeight( 41 );
                state.setFrameSequence( new int[]{0,1} );
                state.setFrameDamage( new int[]{0,0} );
                state.setFrameVelocity( new int[]{0,0} );
                state.setTimeForAnim( 2500 ); // ??
                states.addElement( state );
                
                // WALKING STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_WALKING );
                state.setFrames( images[IMGINDEX_WALKING] );
                state.setFrameWidth( 24 ); state.setFrameHeight( 41 );
                state.setFrameSequence( new int[]{2,0} );
                state.setFrameDamage( new int[]{0,0} );
                state.setFrameVelocity( new int[]{0,0} );
                state.setTimeForAnim( 700 ); // ??
                states.addElement( state );
                
                // DYING STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_DYING );
                state.setFrames( images[IMGINDEX_DYING] );
                state.setFrameWidth( 44 ); state.setFrameHeight( 41 );
                state.setFrameSequence( new int[]{0,0,1,1,1} );
                state.setFrameDamage( new int[]{0,0,0,0,0} );
                state.setFrameVelocity( new int[]{-1,-1,0,0,0} );
                state.setTimeForAnim( 2400 ); // ??
                state.setRepeats( 0 );
                states.addElement( state );
                
                // FALLING STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_FALLING );
                state.setFrames( images[IMGINDEX_FALLING] );
                state.setFrameWidth( 44 ); state.setFrameHeight( 33 );
                state.setFrameSequence( new int[]{0,0,1,2,3,3,4} );
                state.setFrameDamage( new int[]{0,0,0,0,0,0,0} );
                state.setFrameVelocity( new int[]{-1,-1,0,0,0,0,0} );
                state.setTimeForAnim( 2400 ); // ??
                state.setRepeats( 0 );
                states.addElement( state );
                
                // ATTACK 1 STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_ATTACK1 );
                state.setFrames( images[IMGINDEX_ATTACK1] );
                state.setFrameWidth( 31 ); state.setFrameHeight( 41 );
                state.setFrameSequence( new int[]{0} );
                state.setFrameDamage( new int[]{ATTACK1_DAMAGE} );
                state.setFrameVelocity( new int[]{1} );
                state.setTimeForAnim( 180 ); // ??
                state.setRepeats( 0 );
                state.setKeySequence( ActorState.KEY_FIRE_ONLY );
                states.addElement( state );
                
                // ATTACK 2 STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_ATTACK2 );
                state.setFrames( images[IMGINDEX_ATTACK2] );
                state.setFrameWidth( 41 ); state.setFrameHeight( 38 );
                state.setFrameSequence( new int[]{0} );
                state.setFrameDamage( new int[]{ATTACK2_DAMAGE} );
                state.setFrameVelocity( new int[]{1} );
                state.setTimeForAnim( 300 ); // ??
                state.setRepeats( 0 );
                if( facingLeft )
                    state.setKeySequence( ActorState.KEY_FIRE_LEFT );
                else
                    state.setKeySequence( ActorState.KEY_FIRE_RIGHT );
                states.addElement( state );
                
                // ATTACK 3 STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_ATTACK3 );
                state.setFrames( images[IMGINDEX_ATTACK3] );
                state.setFrameWidth( 53 ); state.setFrameHeight( 39 );
                state.setFrameSequence( new int[]{5,4,5,4,3,2,1,0} );
                state.setFrameDamage( new int[]{0,0,0,0,0,ATTACK3_DAMAGE, ATTACK3_DAMAGE, 0} );
                state.setFrameVelocity( new int[]{0,0,0,0,2,0,0,0} );
                state.setTimeForAnim( 2400 ); // ??
                state.setRepeats( 0 );
                if( facingLeft )
                    state.setKeySequence( ActorState.KEY_FIRE_RIGHT );
                else
                    state.setKeySequence( ActorState.KEY_FIRE_LEFT );
                states.addElement( state );
                //</editor-fold>
                break;
                
            case PLAYER_2:
                //<editor-fold defaultstate="collapsed" desc="player 2 state config">
                // STANDING STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_STANDING );
                state.setFrames( images[IMGINDEX_STANDING] );
                state.setFrameWidth( 24 ); state.setFrameHeight( 41 );
                state.setFrameSequence( new int[]{0,1} );
                state.setFrameDamage( new int[]{0,0} );
                state.setFrameVelocity( new int[]{0,0} );
                state.setTimeForAnim( 2500 ); // ??
                states.addElement( state );
                
                // WALKING STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_WALKING );
                state.setFrames( images[IMGINDEX_WALKING] );
                state.setFrameWidth( 23 ); state.setFrameHeight( 41 );
                state.setFrameSequence( new int[]{0,1} );
                state.setFrameDamage( new int[]{0,0} );
                state.setFrameVelocity( new int[]{0,0} );
                state.setTimeForAnim( 550 ); // ??
                states.addElement( state );
                
                // DYING STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_DYING );
                state.setFrames( images[IMGINDEX_DYING] );
                state.setFrameWidth( 40 ); state.setFrameHeight( 41 );
                state.setFrameSequence( new int[]{0,0,1,1,1} );
                state.setFrameDamage( new int[]{0,0,0,0,0} );
                state.setFrameVelocity( new int[]{-1,-1,0,0,0} );
                state.setTimeForAnim( 2400 ); // ??
                state.setRepeats( 0 );
                states.addElement( state );
                
                // FALLING STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_FALLING );
                state.setFrames( images[IMGINDEX_FALLING] );
                state.setFrameWidth( 40 ); state.setFrameHeight( 41 );
                state.setFrameSequence( new int[]{0,0,1,2,3,3} );
                state.setFrameDamage( new int[]{0,0,0,0,0,0} );
                state.setFrameVelocity( new int[]{-1,-1,0,0,0,0} );
                state.setTimeForAnim( 2400 ); // ??
                state.setRepeats( 0 );
                states.addElement( state );
                
                // ATTACK 1 STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_ATTACK1 );
                state.setFrames( images[IMGINDEX_ATTACK1] );
                state.setFrameWidth( 31 ); state.setFrameHeight( 41 );
                state.setFrameSequence( new int[]{1,0} );
                state.setFrameDamage( new int[]{0,ATTACK1_DAMAGE} );
                state.setFrameVelocity( new int[]{0,1} );
                state.setTimeForAnim( 200 ); // ??
                state.setRepeats( 0 );
                state.setKeySequence( ActorState.KEY_FIRE_ONLY );
                states.addElement( state );
                
                // ATTACK 2 STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_ATTACK2 );
                state.setFrames( images[IMGINDEX_ATTACK2] );
                state.setFrameWidth( 38 ); state.setFrameHeight( 41 );
                state.setFrameSequence( new int[]{0,1} );
                state.setFrameDamage( new int[]{0,ATTACK2_DAMAGE} );
                state.setFrameVelocity( new int[]{0,1} );
                state.setTimeForAnim( 310 ); // ??
                state.setRepeats( 0 );
                if( facingLeft )
                    state.setKeySequence( ActorState.KEY_FIRE_LEFT );
                else
                    state.setKeySequence( ActorState.KEY_FIRE_RIGHT );
                states.addElement( state );
                
                // ATTACK 3 STATE (or ATTACK 2b STATE in this case)
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_ATTACK3 );
                state.setFrames( images[IMGINDEX_ATTACK2] );
                state.setFrameWidth( 38 ); state.setFrameHeight( 41 );
                state.setFrameSequence( new int[]{0,1,0,0} );
                state.setFrameDamage( new int[]{0, ATTACK2_DAMAGE, ATTACK2_DAMAGE,0} );
                state.setFrameVelocity( new int[]{0,1,0,0} );
                state.setSpecialEffects( new int[]{-1, SpecialEffect.SPECIAL_EFFECT_HIGH_FIRE_KICK, -1,-1} );
                state.setTimeForAnim( 800 ); // ??
                state.setRepeats( 0 );
                if( facingLeft )
                    state.setKeySequence( ActorState.KEY_FIRE_RIGHT );
                else
                    state.setKeySequence( ActorState.KEY_FIRE_LEFT );
                states.addElement( state );
                //</editor-fold>
                break;
                
            case PLAYER_3:
                //<editor-fold defaultstate="collapsed" desc="player 3 state config">
                // STANDING STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_STANDING );
                state.setFrames( images[IMGINDEX_STANDING] );
                state.setFrameWidth( 24 ); state.setFrameHeight( 41 );
                state.setFrameSequence( new int[]{0,1} );
                state.setFrameDamage( new int[]{0,0} );
                state.setFrameVelocity( new int[]{0,0} );
                state.setTimeForAnim( 2500 ); // ??
                states.addElement( state );
                
                // WALKING STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_WALKING );
                state.setFrames( images[IMGINDEX_WALKING] );
                state.setFrameWidth( 26 ); state.setFrameHeight( 41 );
                state.setFrameSequence( new int[]{1,0} );
                state.setFrameDamage( new int[]{0,0} );
                state.setFrameVelocity( new int[]{0,0} );
                state.setTimeForAnim( 700 ); // ??
                states.addElement( state );
                
                // DYING STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_DYING );
                state.setFrames( images[IMGINDEX_DYING] );
                state.setFrameWidth( 40 ); state.setFrameHeight( 41 );
                state.setFrameSequence( new int[]{0,0,1,1,1} );
                state.setFrameDamage( new int[]{0,0,0,0,0} );
                state.setFrameVelocity( new int[]{-1,-1,0,0,0} );
                state.setTimeForAnim( 2400 ); // ??
                state.setRepeats( 0 );
                states.addElement( state );
                
                // FALLING STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_FALLING );
                state.setFrames( images[IMGINDEX_FALLING] );
                state.setFrameWidth( 40 ); state.setFrameHeight( 41 );
                state.setFrameSequence( new int[]{0,0,1,2,3,3,4} );
                state.setFrameDamage( new int[]{0,0,0,0,0,0,0} );
                state.setFrameVelocity( new int[]{-1,-1,0,0,0,0,0} );
                state.setTimeForAnim( 2400 ); // ??
                state.setRepeats( 0 );
                states.addElement( state );
                
                // ATTACK 1 STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_ATTACK1 );
                state.setFrames( images[IMGINDEX_ATTACK1] );
                state.setFrameWidth( 31 ); state.setFrameHeight( 41 );
                state.setFrameSequence( new int[]{0,1} );
                state.setFrameDamage( new int[]{0,ATTACK1_DAMAGE} );
                state.setFrameVelocity( new int[]{0,1} );
                state.setTimeForAnim( 180 ); // ??
                state.setRepeats( 0 );
                state.setKeySequence( ActorState.KEY_FIRE_ONLY );
                states.addElement( state );
                
                // ATTACK 2 STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_ATTACK2 );
                state.setFrames( images[IMGINDEX_ATTACK2] );
                state.setFrameWidth( 41 ); state.setFrameHeight( 36 );
                state.setFrameSequence( new int[]{0} );
                state.setFrameDamage( new int[]{ATTACK2_DAMAGE} );
                state.setFrameVelocity( new int[]{1} );
                state.setTimeForAnim( 300 ); // ??
                state.setRepeats( 0 );
                if( facingLeft )
                    state.setKeySequence( ActorState.KEY_FIRE_LEFT );
                else
                    state.setKeySequence( ActorState.KEY_FIRE_RIGHT );
                states.addElement( state );
                
                // ATTACK 3 STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_ATTACK3 );
                state.setFrames( images[IMGINDEX_ATTACK3] );
                state.setFrameWidth( 41 ); state.setFrameHeight( 41 );
                state.setFrameSequence( new int[]{0,1,2,3,4} );
                state.setFrameDamage( new int[]{0,0,0,0,ATTACK3_DAMAGE+5} );
                state.setFrameVelocity( new int[]{0,0,2,1,0} );
                state.setTimeForAnim( 1700 ); // ??
                state.setRepeats( 0 );
                if( facingLeft )
                    state.setKeySequence( ActorState.KEY_FIRE_RIGHT );
                else
                    state.setKeySequence( ActorState.KEY_FIRE_LEFT );
                states.addElement( state );
                //</editor-fold>
                break;
                
            case PLAYER_4:
                //<editor-fold defaultstate="collapsed" desc="player 4 state config">
                // STANDING STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_STANDING );
                state.setFrames( images[IMGINDEX_STANDING] );
                state.setFrameWidth( 24 ); state.setFrameHeight( 41 );
                state.setFrameSequence( new int[]{0,1} );
                state.setFrameDamage( new int[]{0,0} );
                state.setFrameVelocity( new int[]{0,0} );
                state.setTimeForAnim( 2500 ); // ??
                states.addElement( state );
                
                // WALKING STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_WALKING );
                state.setFrames( images[IMGINDEX_WALKING] );
                state.setFrameWidth( 24 ); state.setFrameHeight( 41 );
                state.setFrameSequence( new int[]{2,0} );
                state.setFrameDamage( new int[]{0,0} );
                state.setFrameVelocity( new int[]{0,0} );
                state.setTimeForAnim( 700 ); // ??
                states.addElement( state );
                
                // DYING STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_DYING );
                state.setFrames( images[IMGINDEX_DYING] );
                state.setFrameWidth( 44 ); state.setFrameHeight( 41 );
                state.setFrameSequence( new int[]{0,0,1,1,1} );
                state.setFrameDamage( new int[]{0,0,0,0,0} );
                state.setFrameVelocity( new int[]{-1,-1,0,0,0} );
                state.setTimeForAnim( 2400 ); // ??
                state.setRepeats( 0 );
                states.addElement( state );
                
                // FALLING STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_FALLING );
                state.setFrames( images[IMGINDEX_FALLING] );
                state.setFrameWidth( 44 ); state.setFrameHeight( 33 );
                state.setFrameSequence( new int[]{0,0,1,2,3,3,4} );
                state.setFrameDamage( new int[]{0,0,0,0,0,0,0} );
                state.setFrameVelocity( new int[]{-1,-1,0,0,0,0,0} );
                state.setTimeForAnim( 2400 ); // ??
                state.setRepeats( 0 );
                states.addElement( state );
                
                // ATTACK 1 STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_ATTACK1 );
                state.setFrames( images[IMGINDEX_ATTACK1] );
                state.setFrameWidth( 31 ); state.setFrameHeight( 41 );
                state.setFrameSequence( new int[]{0} );
                state.setFrameDamage( new int[]{ATTACK1_DAMAGE} );
                state.setFrameVelocity( new int[]{1} );
                state.setTimeForAnim( 180 ); // ??
                state.setRepeats( 0 );
                state.setKeySequence( ActorState.KEY_FIRE_ONLY );
                states.addElement( state );
                
                // ATTACK 2 STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_ATTACK2 );
                state.setFrames( images[IMGINDEX_ATTACK2] );
                state.setFrameWidth( 41 ); state.setFrameHeight( 38 );
                state.setFrameSequence( new int[]{0} );
                state.setFrameDamage( new int[]{ATTACK2_DAMAGE} );
                state.setFrameVelocity( new int[]{1} );
                state.setTimeForAnim( 300 ); // ??
                state.setRepeats( 0 );
                if( facingLeft )
                    state.setKeySequence( ActorState.KEY_FIRE_LEFT );
                else
                    state.setKeySequence( ActorState.KEY_FIRE_RIGHT );
                states.addElement( state );
                
                // ATTACK 3 STATE
                state = new ActorState( fighter );
                state.setStateID( Actor.STATE_ATTACK3 );
                state.setFrames( images[IMGINDEX_ATTACK3] );
                state.setFrameWidth( 53 ); state.setFrameHeight( 39 );
                state.setFrameSequence( new int[]{5,4,5,4,3,2,1,0} );
                state.setFrameDamage( new int[]{0,0,0,0,0,ATTACK3_DAMAGE, ATTACK3_DAMAGE, 0} );
                state.setFrameVelocity( new int[]{0,0,0,0,2,0,0,0} );
                state.setTimeForAnim( 2400 ); // ??
                state.setRepeats( 0 );
                if( facingLeft )
                    state.setKeySequence( ActorState.KEY_FIRE_RIGHT );
                else
                    state.setKeySequence( ActorState.KEY_FIRE_LEFT );
                states.addElement( state );
                //</editor-fold>
                break;
        }
        
        fighter.addStates( states );
        int startingX;
        if( facingLeft )
            startingX = _worldWidthX2 - (10+fighter.getWidth());
        else
            startingX = _worldWidthX1 + 13;
        
        try{
            fighter.initActor( 20, 1, 1, 2, startingX, getWorldFloor(), facingLeft );
        } catch( Exception e ){
            System.out.println( "unable to initilise player; " + e.getMessage() );
        }
        
        return fighter;
        
    }
    
//</editor-fold>world
    
//<editor-fold defaultstate="collapsed" desc="mutators">
    
    public Fighter getPlayer(){
        return _player;
    }
    
    public Fighter getOpponent(){
        return _opponent;
    }
    
    public int getWorldWidth(){
        return _imgBackdrop.getWidth();
    }
    
    public int getWorldLeftEdge(){
        return _worldWidthX1;
    }
    
    public int getWorldRightEdge(){
        return _worldWidthX2;
    }
    
    public int getWorldFloor(){
        return _worldHeightY2;
    }
    
    public int getWorldRoof(){
        return _worldHeightY1;
    }
    
    public int getWorldsHorzCenter(){
        return _worldsCenterX;
    }
    
    public int getWorldsVertCenter(){
        return _worldsCenterY; 
    }
    
    public boolean inDangerZone(){
        return inDangerZone( getOpponentDistance() );
    }
    
    public boolean inDangerZone( int dis ){
        return getOpponentDistance() <= DANGER_ZONE;
    }
    
    public int getRound(){
        return _round; 
    }
    
    public void playerWon(){
        _roundsWonPlayer++; 
    }
    
    public void opponentWon(){
        _roundsWonOpponent++; 
    }
    
    public int winner(){
        if( _roundsWonOpponent == _roundsWonPlayer )
            return DRAW;
        else if( _roundsWonOpponent > _roundsWonPlayer )
            return OPPONENT_WINS; 
        else
            return PLAYER_WINS; 
    }

    public boolean timeRanOut(){
        return _time <= 0; 
    }
    
    public int getOpponentDistance(){
        if( _player == null && _opponent == null )
            return -1;
        
        int diff = _opponent.getX() - ( _player.getX() + _player.getWidth() );
        
        if( diff < 0 )
            return diff*-1;
        else
            return diff;
    }
    
//</editor-fold>
    
}
